package cn.shengchao.qywx.acl.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.shengchao.qywx.acl.IRuleDomainService;
import cn.shengchao.qywx.infrastrure.po.QywxRuleCondition;
import cn.shengchao.qywx.infrastrure.po.QywxRuleGroup;
import cn.shengchao.qywx.infrastrure.po.QywxRuleMain;
import cn.shengchao.qywx.infrastrure.service.QywxRuleConditionService;
import cn.shengchao.qywx.infrastrure.service.QywxRuleGroupService;
import cn.shengchao.qywx.infrastrure.service.QywxRuleMainService;
import cn.shengchao.rule.base.*;
import cn.shengchao.rule.condition.*;
import cn.shengchao.rule.condition.paramKey.IConditionParamKey;
import cn.shengchao.rule.engine.IRule;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @program: examstarapi
 * @description: 综合接口
 * @author: Xiong weiqiang
 * @create: 2025-04-11 21:38
 */
@Service
@RequiredArgsConstructor
public class IRuleDomainServiceImpl implements IRuleDomainService {
    private final QywxRuleMainService qywxRuleMainService;
    private final QywxRuleGroupService qywxRuleGroupService;
    private final QywxRuleConditionService qywxRuleConditionService;

    @Override
    public List<IRule> fetchDatabaseRules() {
        List<QywxRuleMain> ruleMains=qywxRuleMainService.list(Wrappers.lambdaQuery(QywxRuleMain.class)
                .eq(QywxRuleMain::getRuleStatus,1)
        );
        List<QywxRuleGroup> ruleGroups=qywxRuleGroupService.list(Wrappers.lambdaQuery(QywxRuleGroup.class)
                .in(QywxRuleGroup::getRuleId,CollUtil.isEmpty(ruleMains)? List.of(-1L):ruleMains.stream().map(QywxRuleMain::getId).collect(Collectors.toSet()))
        );
        List<QywxRuleCondition> ruleConditions=qywxRuleConditionService.list(Wrappers.lambdaQuery(QywxRuleCondition.class)
                .in(QywxRuleCondition::getGroupId,CollUtil.isEmpty(ruleGroups)? List.of(-1L):ruleGroups.stream().map(QywxRuleGroup::getId).collect(Collectors.toSet()))
        );
        List<IRule> rules= compositeRules(ruleMains,ruleGroups,ruleConditions);
        CollUtil.sort(rules, Comparator.comparingInt(IRule::getPriority));
        //用reversed 是为了让优先级高的规则先执行，因为规则引擎是按照优先级从高到低执行的
        //但会换List
        return new ArrayList<>(rules.reversed());
    }

    @Override
    public IRule fetchRuleById(Long id) {
        QywxRuleMain ruleMain=qywxRuleMainService.getById(id);
        List<QywxRuleGroup> ruleGroups=qywxRuleGroupService.list(Wrappers.lambdaQuery(QywxRuleGroup.class)
                .eq(QywxRuleGroup::getRuleId,ruleMain.getId())
        );
        List<QywxRuleCondition> ruleConditions=qywxRuleConditionService.list(Wrappers.lambdaQuery(QywxRuleCondition.class)
                .in(QywxRuleCondition::getGroupId,CollUtil.isEmpty(ruleGroups)? List.of(-1L):ruleGroups.stream().map(QywxRuleGroup::getId).collect(Collectors.toSet()))
        );
        List<IRule> rules= compositeRules(CollUtil.newArrayList(ruleMain),ruleGroups,ruleConditions);
        if (CollUtil.isNotEmpty(rules)){
            return rules.getFirst();
        }
        return null;
    }

    private List<IRule> compositeRules(List<QywxRuleMain> ruleMains,
                                       List<QywxRuleGroup> ruleGroups,
                                       List<QywxRuleCondition> ruleConditions) {
        if (CollUtil.isNotEmpty(ruleMains)&&CollUtil.isNotEmpty(ruleGroups)&&CollUtil.isNotEmpty(ruleConditions)){
            List<IRule> rules=new ArrayList<>();
            Map<Long, List<QywxRuleGroup> > groupMap = ruleGroups.stream().collect(Collectors.groupingBy(QywxRuleGroup::getRuleId));
            Map<Long, List<QywxRuleCondition>> conditionMap = ruleConditions.stream().collect(Collectors.groupingBy(QywxRuleCondition::getGroupId));
            if (CollUtil.isEmpty(groupMap)){
                return List.of();
            }
            for (QywxRuleMain ruleMain : ruleMains) {
                DataRule rule = new DataRule();
                rule.setId(ruleMain.getId());
                rule.setName(ruleMain.getRuleName());
                rule.setPriority(ruleMain.getPriority());
                rule.setStartTime(LocalDateTimeUtil.of(ruleMain.getValidStartTime()));
                rule.setEndTime(LocalDateTimeUtil.of(ruleMain.getValidEndTime()));
                List<ConditionGroup> conditionGroups = new ArrayList<>();
                List<QywxRuleGroup> groups = groupMap.get(ruleMain.getId());
                if (CollUtil.isNotEmpty(groups)){
                    for (QywxRuleGroup group : groups) {
                        String actionType = group.getActionType();
                        IAction iAction= buildAction(actionType,group.getActionValue());
                        ConditionGroup conditionGroup = new ConditionGroup();
                        conditionGroup.setGroupId(group.getId());
                        conditionGroup.setRuleId(ruleMain.getId());
                        conditionGroup.setAction(iAction);
                        List<ICondition> conditionList=new ArrayList<>();
                        for (QywxRuleCondition condition : conditionMap.get(group.getId())) {
                            String conditionParamKey = condition.getConditionParamKey();
                            ICondition iCondition= buildCondition(conditionParamKey);
                            iCondition.setValueTypeKey(condition.getValueTypeKey());
                            iCondition.setMatchValue(condition.getMatchValue());
                            iCondition.setMatchTypeKey(condition.getMatchTypeKey());
                            conditionList.add(iCondition);
                        }
                        conditionGroup.setConditions(conditionList);
                        conditionGroups.add(conditionGroup);
                    }
                }

                rule.setConditionGroups(conditionGroups);
                rules.add(rule);
            }
            return rules;
        }
        return List.of();
    }

    private IAction buildAction(String actionType,String actionValue){
        IAction action=null;
        ActionType actionTypeEnum = ActionType.valueOf(actionType);
        switch (actionTypeEnum){
            case SPECIFIC_USER -> action=new SpecificUserAction();
            case INVITER -> action=new AssignInviteAction();
            case CUSTOMER_GROUP -> action=new CustomerGroupAction();
        }
        action.setActionValue(actionValue);
        return action;
    }

    private ICondition buildCondition(String conditionParamKey){
        ICondition condition=null;
        switch (conditionParamKey){
            case IConditionParamKey.ENTRY_URI -> condition=new EntryUriCondition();
            case IConditionParamKey.PRODUCT_ID -> condition=new ProductCondition();
            case IConditionParamKey.USER_SOURCE_CHANNEL -> condition=new UserSourceChannelCondition();
            case IConditionParamKey.VIP_LEVELS -> condition=new VipLevelsCondition();
            case IConditionParamKey.REGISTER_DATE_RANGE -> condition=new RegisterDateRangeCondition();
        }
        return condition;
    }
}